package com.example.libannotationprocessor

import com.example.libannotation.BindView
import com.google.auto.service.AutoService
import java.io.Writer
import javax.annotation.processing.*
import javax.lang.model.SourceVersion
import javax.lang.model.element.TypeElement
import javax.lang.model.element.VariableElement
import javax.tools.Diagnostic

/**
 * 注解处理器，用来生成代码的
 */
@AutoService(Processor::class)
class BindViewProcessor : AbstractProcessor() {
    //1.支持的版本
    override fun getSupportedSourceVersion(): SourceVersion? {
        return SourceVersion.latestSupported()
    }

    //2.能用来处理哪些注解
    override fun getSupportedAnnotationTypes(): Set<String>? {
        val types: MutableSet<String> = HashSet()
        //添加这个注解处理器处理的注解
        types.add(BindView::class.java.canonicalName)
        return types
    }

    //3.定义一个用来生成APT目录下面的文件的对象
    var filer: Filer? = null

    //初始化，有需要初始化的代码在这里执行
    @Synchronized
    override fun init(processingEnvironment: ProcessingEnvironment) {
        super.init(processingEnvironment)
        filer = processingEnvironment.filer
    }

    override fun process(set: MutableSet<out TypeElement>?, roundEnvironment: RoundEnvironment?): Boolean {
        //这个类默认会回调三次，这里判断一下，如果set是空的就不要处理了
        if(set==null||set.size==0)return false
        //注解处理器打印的方法，这个会在build的时候执行
        processingEnv.messager.printMessage(Diagnostic.Kind.NOTE,"========")

        //获取APP中所有用到了BindView注解的对象
        val elementsAnnotatedWith = roundEnvironment!!.getElementsAnnotatedWith(
            BindView::class.java
        )

        // TypeElement//类
        // ExecutableElement//方法
        // VariableElement//属性
        // 开始对elementsAnnotatedWith进行分类
        val map: MutableMap<String, MutableList<VariableElement>> = HashMap()
        for (element in elementsAnnotatedWith) {
            val variableElement = element as VariableElement
            val activityName = variableElement.enclosingElement.simpleName.toString()
            val aClass: Class<*> = variableElement.enclosingElement.javaClass
            var variableElements = map[activityName]
            if (variableElements == null) {
                variableElements = ArrayList()
                map[activityName] = variableElements
            }
            variableElements.add(variableElement)
        }


        //开始生成文件
//        package com.example.butterknife_framework_demo;
//        import com.example.butterknife_framework_demo.IBinder;
//        public class MainActivity_ViewBinding implements IBinder<com.example.butterknife_framework_demo.MainActivity> {
//            @Override
//            public void bind(com.example.butterknife_framework_demo.MainActivity target) {
//                target.textView = (android.widget.TextView) target.findViewById(2131165359);
//
//            }
//        }


        //开始生成文件
//        package com.example.butterknife_framework_demo;
//        import com.example.butterknife_framework_demo.IBinder;
//        public class MainActivity_ViewBinding implements IBinder<com.example.butterknife_framework_demo.MainActivity> {
//            @Override
//            public void bind(com.example.butterknife_framework_demo.MainActivity target) {
//                target.textView = (android.widget.TextView) target.findViewById(2131165359);
//
//            }
//        }
        if (map.isNotEmpty()) {
            var writer: Writer? = null
            val iterator: Iterator<String> = map.keys.iterator()
            while (iterator.hasNext()) {
                val activityName = iterator.next()
                val variableElements: List<VariableElement>? = map[activityName]
                //得到包名
                val enclosingElement = variableElements!![0].enclosingElement as TypeElement
                val packageName =
                    processingEnv.elementUtils.getPackageOf(enclosingElement).toString()
                try {
                    val sourceFile =
                        filer!!.createSourceFile(packageName + "." + activityName + "_ViewBinding")
                    writer = sourceFile.openWriter()
                    //        package com.example.dn_butterknife;
                    writer.write("package $packageName;\n")
                    //        import com.example.dn_butterknife.IBinder;
                    writer.write("import $packageName.IBinder;\n")
                    //        public class MainActivity_ViewBinding implements IBinder<
                    //        com.example.dn_butterknife.MainActivity>{
                    writer.write(
                        "public class " + activityName + "_ViewBinding implements IBinder<" +
                                packageName + "." + activityName + ">{\n"
                    )
                    //            public void bind(com.example.dn_butterknife.MainActivity target) {
                    writer.write(
                        (" @Override\n" +
                                " public void bind(" + packageName + "." + activityName + " target){")
                    )
                    //target.tvText=(android.widget.TextView)target.findViewById(2131165325);
                    for (variableElement: VariableElement in variableElements) {
                        //得到名字
                        val variableName = variableElement.simpleName.toString()
                        //得到ID
                        val id: Int = variableElement.getAnnotation(BindView::class.java).value
                        //得到类型
                        val typeMirror = variableElement.asType()
                        writer.write("target.$variableName=($typeMirror)target.findViewById($id);\n")
                    }
                    writer.write("\n}}")
                } catch (e: Exception) {
                    e.printStackTrace()
                } finally {
                    if (writer != null) {
                        try {
                            writer.close()
                        } catch (e: Exception) {
                            e.printStackTrace()
                        }
                    }
                }
            }
        }








        return false
    }




}